﻿// CPreImport.cpp: 实现文件
//

#include "pch.h"
#include "DBBrowser.h"
#include "DBBrowserDoc.h"
#include "CPreImportDlg.h"
#include "afxdialogex.h"
#include "dbother.h"
#include "ClassView.h"

// CMyListBox

IMPLEMENT_DYNAMIC(CMyListBox, CVSListBox)

CMyListBox::CMyListBox()
{

}

CMyListBox::~CMyListBox()
{
}

void CMyListBox::OnAfterMoveItemDown(int iItem)
{
	auto p = (CPreImportDlg*)GetParent();
	for (int i = 0; i < GetCount(); i++) {
		for (int j = 0; j < p->m_viewdata.size(); j++) {
			if (p->m_viewdata[j][0] == CString(std::to_wstring(i + 1).data())) {
				int k = std::find(p->colinfo.begin(), p->colinfo.end(), GetItemText(i)) - p->colinfo.begin();
				if (j != k) { p->m_viewdata[j].swap(p->m_viewdata[k]); }
				break;
			}
		}
	}
	p->m_ViewList.RedrawItems(0, 30);
	p->CodeGenSwitch();
}

void CMyListBox::OnAfterMoveItemUp(int iItem)
{
	auto p = (CPreImportDlg*)GetParent();
	for (int i = 0; i < GetCount(); i++) {
		for (int j = 0; j < p->m_viewdata.size(); j++) {
			if (p->m_viewdata[j][0] == CString(std::to_wstring(i + 1).data())) {
				int k = std::find(p->colinfo.begin(), p->colinfo.end(), GetItemText(i)) - p->colinfo.begin();
				if (j != k) { p->m_viewdata[j].swap(p->m_viewdata[k]); }
				break;
			}
		}
	}
	p->m_ViewList.RedrawItems(0, 30);
	p->CodeGenSwitch();
}

BEGIN_MESSAGE_MAP(CMyListBox, CVSListBox)
END_MESSAGE_MAP()

// CMyListBox 消息处理程序


// CPreImport 对话框

IMPLEMENT_DYNAMIC(CPreImportDlg, CDialogEx)

CPreImportDlg::CPreImportDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_PREIMPORT, pParent)
{

}

CPreImportDlg::~CPreImportDlg()
{
}

void CPreImportDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_MFCVSLISTBOX1, m_List);
	DDX_Control(pDX, IDC_DELIMITER, m_delimiter);
	DDX_Control(pDX, IDC_VIEWLIST, m_ViewList);
	DDX_Control(pDX, IDC_CIKUNAME, m_cksel);
	DDX_Control(pDX, IDC_DUOYI, m_isduoyi);
	DDX_Control(pDX, IDC_EDIT2, m_def);
	DDX_Control(pDX, IDC_CODEGEN, m_codegen);
	DDX_Control(pDX, IDC_EDIT_RULES, m_rules);
	DDX_Control(pDX, IDC_CHECK_CUSTOMPATH, m_custompath);
}


BEGIN_MESSAGE_MAP(CPreImportDlg, CDialogEx)
	ON_NOTIFY(LVN_GETDISPINFO, IDC_VIEWLIST, &CPreImportDlg::OnGetdispinfoViewlist)
	ON_CBN_SELCHANGE(IDC_CIKUNAME, &CPreImportDlg::OnSelchangeCikuname)
	ON_BN_CLICKED(IDC_DUOYI, &CPreImportDlg::FreshPreView)
	ON_CBN_EDITUPDATE(IDC_DELIMITER, &CPreImportDlg::OnCbnEditUpdateDelimiter)
	ON_CBN_SELENDOK(IDC_DELIMITER, &CPreImportDlg::OnCbnSelchangeDelimiter)
	ON_EN_CHANGE(IDC_EDIT2, &CPreImportDlg::OnChangeEdit2)
	ON_CBN_KILLFOCUS(IDC_CIKUNAME, &CPreImportDlg::OnKillfocusCikuname)
	ON_CBN_SELCHANGE(IDC_CODEGEN, &CPreImportDlg::OnSelchangeCodegen)
	ON_EN_KILLFOCUS(IDC_EDIT_RULES, &CPreImportDlg::OnKillfocusEditRules)
	ON_BN_CLICKED(IDC_CHECK_CUSTOMPATH, &CPreImportDlg::OnBnClickedCheckCustompath)
END_MESSAGE_MAP()


// CPreImport 消息处理程序


BOOL CPreImportDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// TODO:  在此添加额外的初始化
	SetWindowTheme(m_ViewList.m_hWnd, L"Explorer", 0);
	m_delimiter.LimitText(1);
	m_ViewList.SetExtendedStyle(m_ViewList.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);
	m_delimiter.AddString(_T("Tab"));
	m_delimiter.AddString(_T(","));
	m_delimiter.AddString(_T("空格"));
	m_delimiter.AddString(_T(";"));
	m_delimiter.AddString(_T("="));
	m_delimiter.SelectString(0, _T("Tab"));
	for (size_t i = 0; i < m_tbl.size(); i++) {
		m_cksel.AddString(m_tbl[i]);
	}
	m_cksel.SelectString(0, m_tbl[0]);
	std::string encoding = Hanzi::Dict::GuessEncoding(buffer, min(512, dwsize));
	int cur = 0;
	m_viewcode.push_back(_T(""));
	for (int i = 0; i < 36; i++) {
		m_viewcode.push_back(_T(""));
		auto p = (char*)memchr(&buffer[cur], '\n', dwsize - cur);
		if (!p) {
			cur = dwsize;
			break;
		}
		else
			cur += p - &buffer[cur] + 1;
	}
	cur = min(dwsize, cur);
	prebuffer.clear();
	if (encoding == "utf16be") {

	}
	else if (encoding == "utf16le") {
		prebuffer = std::wstring((wchar_t*)buffer, cur / 2);
	}
	else {
		wchar_t *res = new wchar_t[cur * 2];
		wmemset(res, 0, cur * 2);
		MultiByteToWideChar(encoding == "utf8" ? CP_UTF8 : 936, NULL, buffer, cur, res, cur * 2);
		prebuffer = res;
		delete[] res;
	}
	m_rules.SetWindowTextW(rules);
	m_rules.EnableWindow(FALSE);
	m_cksel.GetWindowTextW(selck);
	Predataview();
	return TRUE;  // return TRUE unless you set the focus to a control
				  // 异常: OCX 属性页应返回 FALSE
}


void CPreImportDlg::OnGetdispinfoViewlist(NMHDR *pNMHDR, LRESULT *pResult)
{
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码
	int iItemIndex = pDispInfo->item.iItem + 1 + (firstishead && !isduoyi);
	int iSubItemIndex = pDispInfo->item.iSubItem;
	if (iSubItemIndex < m_viewdata.size() && iItemIndex < m_viewdata[iSubItemIndex].size()) {
		if (iSubItemIndex == 0 && codegen != _T("无")) {
			pDispInfo->item.pszText = (LPWSTR)m_viewcode[iItemIndex].GetString();
		}
		else { pDispInfo->item.pszText = (LPWSTR)m_viewdata[iSubItemIndex][iItemIndex].GetString(); }
	}
	*pResult = 0;
}


void CPreImportDlg::OnSelchangeCikuname()
{
	m_cksel.GetLBText(m_cksel.GetCurSel(), selck);
	FreshPreView();
}

void CPreImportDlg::FreshPreView()
{
	// TODO: 在此添加控件通知处理程序代码

	auto pDoc = (CDBBrowserDoc*)((CFrameWndEx*)AfxGetApp()->m_pMainWnd)->GetActiveDocument();
	auto db = &pDoc->m_db;
	isduoyi = m_isduoyi.GetCheck();
	if (lasttbl != selck) {
		regetinfo:
		std::wcmatch res;
		std::regex_match(selck.GetString(), res, std::wregex(L"^([^\\.]+\\.)?'?([^\\.]+?)'?$"));
		std::wstring sql = L"PRAGMA " + std::wstring(res[1].first, res[1].second) + L"table_info('" + std::wstring(res[2].first, res[2].second) + L"')";

		bool ispy = false;
		colinfo.clear();
		try {
			*db << sql >> [&](std::wstring cid, std::wstring name) { if (name == L"jp") { ispy = true; } else { colinfo.push_back(name.data()); } };
		}
		catch (sqlite::sqlite_exception) {
			m_cksel.SetWindowTextW(lasttbl);
			return;
		}
		if (colinfo.size() == 0 && selck != _T("")) {
			auto ret = MessageBoxW(L"词库不存在，是否创建？", NULL, MB_OKCANCEL | MB_ICONQUESTION);
			if (ret == IDCANCEL) {
				if (m_cksel.GetCount() > 1) {
					m_cksel.DeleteString(m_cksel.FindString(0, selck));
					m_cksel.SetCurSel(0); m_cksel.GetWindowTextW(selck);
					goto regetinfo;
				}
				else { m_cksel.SetWindowTextW(L""); return; }
			}
			std::wstring tbl = std::wstring(res[2].first, res[2].second);
			std::wstring sql2 = pDoc->GetDefaultCreateSQL(selck);
			try {
				if (pDoc->m_autotrans && !pDoc->m_transaction) {
					pDoc->m_db << "begin;";
					pDoc->m_transaction = true;
				}
				*db << sql2;
				*db << sql >> [&](std::wstring cid, std::wstring name) { if (name == L"jp") { ispy = true; } else { colinfo.push_back(name.data()); } };
				((CClassView*)((CFrameWndEx*)AfxGetMainWnd())->GetPane(ID_VIEW_CLASSVIEW))->ReBuildTree();
				if (colinfo.size() == 0) { return; }
			}
			catch (sqlite::sqlite_exception& e) {
				MessageBoxA(*AfxGetApp()->m_pMainWnd, e.get_msg(), 0, 0);
				return;
			}
		}
		ispy = std::regex_search(selck.GetString(), std::wregex(L"pinyin", std::wregex::icase)) ? true : false;
		if (colinfo.size() < 3) { m_isduoyi.EnableWindow(FALSE); m_isduoyi.SetCheck(0); }
		else { m_isduoyi.EnableWindow(TRUE); }
		for (int i = m_codegen.GetCount(); i > 0; i--) { m_codegen.DeleteString(0); }
		m_codegen.AddString(_T("无"));
		if (ispy) { m_codegen.AddString(_T("拼音")); }
		else if (!std::regex_search(selck.GetString(), std::wregex(L"functions|english|cliphistory|symbol", std::wregex::icase))) {
			for (auto s : { _T("五笔"),_T("郑码"),_T("自定义") }) {
				m_codegen.AddString(s);
			}
		}
		m_codegen.SelectString(0, _T("无")); codegen = _T("无");
		m_viewdata.clear();
		for (int i = m_List.GetCount(); i > 0; i--) {
			m_List.RemoveItem(0);
			m_ViewList.DeleteColumn(0);
		}
		if (firstishead) {
			for (size_t i = 0; i < colinfo.size(); i++) {
				m_ViewList.InsertColumn(i, colinfo[i], 0, 100);
			}
			for (size_t i = 0; i < m_predata[0].size(); i++) {
				m_List.AddItem(m_predata[0][i]);
			}
			for (int i = 0; i < colinfo.size(); i++) {
				if (std::find(m_predata[0].begin(), m_predata[0].end(), colinfo[i]) == m_predata[0].end()) {
					m_List.AddItem(colinfo[i]);
				}
			}
		}
		else {
			for (size_t i = 0; i < colinfo.size(); i++) {
				m_ViewList.InsertColumn(i, colinfo[i], 0, 100);
				m_List.AddItem(colinfo[i]);
			}
		}
		lasttbl = selck;
	}
	m_viewdata.clear();
	if (isduoyi) {
		m_List.EnableWindow(FALSE);
		for (int coli = 1; coli < m_List.GetCount() + 1; coli++) {
			std::vector<CString> col;
			col.push_back(std::to_wstring(coli).data());
			m_viewdata.push_back(col);
		}
		int coli = 0, rowi = 0;
		for (size_t i = 0; i < m_predata.size(); i++) {
			size_t len = m_predata[i].size();
			for (size_t j = 1; j < len; j++) {
				m_viewdata[0].push_back(m_predata[i][0]);
				m_viewdata[1].push_back(m_predata[i][j]);
				m_viewdata[2].push_back(std::to_wstring(len - j).data());
				for (int k = 3; k < colinfo.size(); k++) { m_viewdata[k].push_back(_T("")); }
			}
		}
	}
	else {
		m_List.EnableWindow(TRUE);
		for (int coli = 1; coli < m_List.GetCount() + 1; coli++) {
			std::vector<CString> col;
			col.push_back(std::to_wstring(coli).data());
			m_viewdata.push_back(col);
			for (size_t i = 0; i < m_predata.size(); i++) {
				if (coli - 1 < m_predata[i].size()) {
					m_viewdata[coli - 1].push_back(m_predata[i][coli - 1]);
				}
				else { m_viewdata[coli - 1].push_back(L""); }
			}
		}

		for (int i = 0; i < m_List.GetCount(); i++) {
			for (int j = 0; j < m_viewdata.size(); j++) {
				if (m_viewdata[j][0] == CString(std::to_wstring(i + 1).data())) {
					int k = std::find(colinfo.begin(), colinfo.end(), m_List.GetItemText(i)) - colinfo.begin();
					if (j != k) { m_viewdata[j].swap(m_viewdata[k]); }
					break;
				}
			}
		}
	}

	if (m_viewdata.size() > 0) {
		m_ViewList.SetItemCount(min(30, m_viewdata[0].size() - 1));
		m_ViewList.RedrawItems(0, 30);
		CodeGenSwitch();
	}
}


void CPreImportDlg::CodeGenSwitch()
{
	std::wstring t = selck.GetString();
	if (m_viewdata[0].size() > 1 && m_viewdata[0][1] == L"") {
		if (std::regex_search(t, std::wregex(L"pinyin", std::wregex::icase))) {
			m_codegen.SelectString(0, _T("拼音"));
		}
		else if (std::regex_search(t, std::wregex(L"wubi|五笔", std::wregex::icase))) {
			m_codegen.SelectString(0, _T("五笔"));
		}
		else if (std::regex_search(t, std::wregex(L"zhengma|郑码", std::wregex::icase))) {
			m_codegen.SelectString(0, _T("郑码"));
		}
		else { m_codegen.SelectString(0, _T("无")); }
	}
	else { m_codegen.SelectString(0, _T("无")); }
	m_codegen.GetWindowTextW(codegen);
	if (codegen == _T("无"))
		m_rules.EnableWindow(FALSE);
	else
		CodeGen();
	m_ViewList.RedrawItems(0, 30);
}


void CPreImportDlg::Predataview(char del)
{
	// TODO: 在此处添加实现代码.
	csv::Reader<wchar_t> csv;
	csv.parse(prebuffer);
	if (del == '\0') {
		size_t t = prebuffer.find_first_of(L"\\r\\n");
		if (t != std::wstring::npos && prebuffer[t] == '\\r' && prebuffer[t + 1] == '\\n')
			CRLF = 2;
		bool quo = true; delimiter = '\t';
		for (size_t i = 0; i < prebuffer.size(); i++) {
			if (prebuffer[i] == '"')
				quo = !quo;
			else if (quo && (prebuffer[i] == '\t' || prebuffer[i] == ' ' || prebuffer[i] == ',' || prebuffer[i] == '=' || prebuffer[i] == ';')) {
				delimiter = prebuffer[i];
				break;
			}
		}
		csv.infos.delimiter = delimiter;
		switch (delimiter)
		{
		case '\t':
			m_delimiter.SelectString(0, L"Tab");
			break;
		case ' ':
			m_delimiter.SelectString(0, L"空格");
			break;
		case '=':
			m_delimiter.SelectString(0, L"=");
			break;
		case ',':
			m_delimiter.SelectString(0, L",");
			break;
		case ';':
			m_delimiter.SelectString(0, L";");
			break;
		}
	}
	else { delimiter = del; csv.infos.delimiter = delimiter; }

	int i = 0; isduoyi = FALSE;
	std::vector<std::vector<CString>> predata;
	for (auto row : csv) {
		if (row.size() <= 0) { continue; }
		std::vector<CString> rowdata;
		std::wstring celldata;
		rowdata.clear();
		int n = 0;
		for (auto cell : row) {
			n++; celldata.clear();
			cell.read_value(celldata);
			rowdata.push_back(celldata.data());
			if (!isduoyi&&n > 3 && std::regex_search(rowdata[3].GetString(), std::wregex(L"[\\x4f00-\\x9f00]"))) { isduoyi = TRUE; }
		}
		predata.push_back(rowdata);
		i++;
		if (i > 26) { break; }
	}
	m_predata.swap(predata);
	CString headtext("|key|value|weight|comment|");
	firstishead = FALSE;
	if (m_predata.size() > 0) {
		firstishead = TRUE;
		for (size_t i = 0; i < m_predata[0].size(); i++) {
			if (headtext.Find(CString("|") + m_predata[0][i] + CString("|")) == -1) {
				firstishead = FALSE; break;
			}
		}
	}
	m_isduoyi.SetCheck(isduoyi);
	FreshPreView();
}


void CPreImportDlg::OnCbnSelchangeDelimiter()
{

	// TODO: 在此添加控件通知处理程序代码
	CString t;
	m_delimiter.GetLBText(m_delimiter.GetCurSel(), t);
	Predataview(t == L"Tab" ? '\t' : t == L"空格" ? ' ' : t[0]);
}

void CPreImportDlg::OnCbnEditUpdateDelimiter()
{
	CString t;
	m_delimiter.GetWindowTextW(t);
	if (t == L"") { return; }
	Predataview(t == L"Tab" ? '\t' : t == L"空格" ? ' ' : t[0]);
}


void CPreImportDlg::OnChangeEdit2()
{
	// TODO:  如果该控件是 RICHEDIT 控件，它将不
	// 发送此通知，除非重写 CDialogEx::OnInitDialog()
	// 函数并调用 CRichEditCtrl().SetEventMask()，
	// 同时将 ENM_CHANGE 标志“或”运算到掩码中。

	// TODO:  在此添加控件通知处理程序代码
	m_def.GetWindowTextW(def);
}


void CPreImportDlg::OnKillfocusCikuname()
{
	// TODO: 在此添加控件通知处理程序代码
	m_cksel.GetWindowTextW(selck);
	FreshPreView();
}


void CPreImportDlg::OnOK()
{
	// TODO: 在此添加专用代码和/或调用基类
	if (codegen == _T("无") && pGen) { delete pGen; pGen = nullptr; }
	CDialogEx::OnOK();
}


void CPreImportDlg::OnSelchangeCodegen()
{
	// TODO: 在此添加控件通知处理程序代码
	m_codegen.GetWindowTextW(codegen);
	if (codegen == _T("无"))
		m_rules.EnableWindow(FALSE);
	else
		CodeGen();
	m_ViewList.RedrawItems(0, 30);
}


void CPreImportDlg::LoadDictFromRes(WORD ID) {
	HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(ID), L"dict");
	DWORD dwSize = SizeofResource(NULL, hRsrc);
	HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
	LPVOID pBuffer = LockResource(hGlobal);
	if (pGen) { pGen->GetDict()->LoadDict((const char*)pBuffer, dwSize); }
	else { pGen = new Hanzi::CodeGenerater((const char*)pBuffer, dwSize); }
	GlobalUnlock(hGlobal);
}


void CPreImportDlg::CodeGen()
{
	// TODO: 在此添加控件通知处理程序代码
	if (!pGen && PathFileExistsW(dictpath)) {
		pGen = new Hanzi::CodeGenerater(dictpath.GetString());
	}
	else if (!m_custompath.GetCheck()) {
		std::wcmatch res;
		std::regex_match(selck.GetString(), res, std::wregex(L"^([^\\.]+\\.)?'?([^\\.]+?)'?$"));
		CString userdict;
		std::wstring tb = res[2];
		userdict.Format(_T("%sData\\@mb_%s.txt"), ((CDBBrowserApp*)AfxGetApp())->m_exepath.data(), tb.data());
		if (codegen == _T("拼音")) {
			LoadDictFromRes(IDR_DICT_PINYIN);
			if (PathFileExistsW(userdict))
				pGen->GetDict()->LoadDict(userdict.GetString());
		}
		else if (codegen == _T("五笔")) {
			LoadDictFromRes(selck.Find(_T("98")) != -1 || selck.Find(_T("九八")) != -1 ? IDR_DICT_WB98 : IDR_DICT_WB86);
			if (PathFileExistsW(userdict))
				pGen->GetDict()->LoadDict(userdict.GetString());
		}
		else if (codegen == _T("郑码")) {
			LoadDictFromRes(IDR_DICT_ZHENGMA);
			if (PathFileExistsW(userdict))
				pGen->GetDict()->LoadDict(userdict.GetString());
		}
		else if (pGen) { pGen->GetDict()->dict.clear(); }
		else { std::string t = ""; pGen = new Hanzi::CodeGenerater(t.data(), t.size()); }
	}
	if (codegen == _T("拼音")) { pGen->SetMode("pinyin"); }
	else if (codegen == _T("五笔")) { pGen->SetMode("wubi"); }
	else if (codegen == _T("郑码")) { pGen->SetMode("zhengma"); }
	else if (codegen == _T("自定义")) { pGen->SetCustomRules(sqlite::utility::utf16_to_utf8(rules.GetString())); }
	m_rules.EnableWindow(codegen == _T("自定义"));
	if (m_viewdata.size() > 1) {
		for (int i = 1; i < min(m_viewcode.size(), m_viewdata[1].size()); i++) {
			std::wstring t = m_viewdata[1][i].GetString();
			m_viewcode[i] = pGen->GetCode(t)[0].data();
		}
		m_ViewList.RedrawItems(0, 30);
	}
}


void CPreImportDlg::OnKillfocusEditRules()
{
	// TODO: 在此添加控件通知处理程序代码
	m_rules.GetWindowTextW(rules);
	CodeGen();
}


void CPreImportDlg::OnBnClickedCheckCustompath()
{
	// TODO: 在此添加控件通知处理程序代码
	if (m_custompath.GetCheck()) {
		CFileDialog dlg(TRUE, _T("*.*"), NULL,
			OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY,
			_T("文本文件 (*.*)|*.*||"), NULL);
		dlg.m_ofn.lpstrTitle = _T("选择编码文件");
		if (dlg.DoModal() == IDOK) {
			dictpath = dlg.GetPathName();
			if (pGen) { pGen->GetDict()->dict.clear(), pGen->GetDict()->LoadDict(dictpath.GetString()); }
			else { pGen = new Hanzi::CodeGenerater(dictpath.GetString()); }
			std::unordered_map<std::string, Hanzi::Codes>::iterator it;
			if (pGen->GetDict()->Find("@rules", it) && m_codegen.SelectString(0, _T("自定义")) != CB_ERR) {
				int len = MultiByteToWideChar(CP_UTF8, NULL, it->second[0].data(), it->second[0].size(), NULL, NULL);
				wchar_t *buf = new wchar_t[len + 1];
				MultiByteToWideChar(CP_UTF8, NULL, it->second[0].data(), it->second[0].size(), buf, len);
				buf[len] = '\0';
				CString r = buf;
				delete[] buf;
				r.Replace(_T("\n"), _T("\r\n"));
				codegen = _T("自定义");
				m_rules.SetWindowTextW(r);
				pGen->SetCustomRules(it->second[0]);
			}
			CodeGen();
		}
		else { m_custompath.SetCheck(0); }
	}
}
